﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace FirstPerson
{
    /// <summary>
    /// A terrain defined by a set of vertices.
    /// </summary>
    public class Terrain : ERF.GeometricGameObject
    {
        private Texture2D grass;
        private Texture2D mountain;
        private Texture2D mud;
        private float maxHeight;
        private Vector2 offset;
        private Vector2 size;
        private int horizontalVertices;
        private int verticalVertices;
        private float horizontalSpacing, verticalSpacing;

        /// <summary>
        /// Creates a new instance of the Terrain.
        /// </summary>
        /// <param name="game">The game that this instance belongs to</param>
        /// <param name="vertices">The set of vertices that define the terrain.</param>
        /// <param name="indices">The set of indices that defines how to bind the vertices together.</param>
        /// <param name="offsetX">The position offset in X of the terrain.</param>
        /// <param name="offsetY">The position offset in Z of the terrain.</param>
        /// <param name="width">The width of the terrain.</param>
        /// <param name="height">The height of the terrain.</param>
        /// <param name="maxHeight">The max height used when creating the terrain.</param>
        /// <param name="waterLevel">The altitude of the water. (NOT CURRENTLY USED)</param>
        /// <param name="horizontalVertices">The number of vertices in the X dimension.</param>
        /// <param name="verticalVertices">The number of vertices in the Y dimension.</param>
        public Terrain(ERF.ERFGame game, ref VertexPositionNormalTexture[] vertices, ref ushort[] indices, float offsetX, float offsetY, float width, float height, float maxHeight, int horizontalVertices, int verticalVertices, float horizontalSpacing, float verticalSpacing)
            : base(game)
        {
            base.Vertices = vertices;
            base.Indices = indices;
            base.PrimitiveCount = indices.Length / 3;
            base.PrimitiveType = PrimitiveType.TriangleList;
            this.maxHeight = maxHeight;
            this.horizontalVertices = horizontalVertices;
            this.verticalVertices = verticalVertices;
            this.offset = new Vector2(offsetX, offsetY);
            this.size = new Vector2(width, height);
            this.horizontalSpacing = horizontalSpacing;
            this.verticalSpacing = verticalSpacing;

            // Create the effect used for this terrain.
            BasicTerrainShader effect = new BasicTerrainShader(game);
            this.grass = game.Content.Load<Texture2D>("Textures\\grass");
            
            // We dont want any mountains, so we'll just use the grass texture here aswell.
            this.mountain = game.Content.Load<Texture2D>("Textures\\grass");
            this.mud = game.Content.Load<Texture2D>("Textures\\Sand");
            effect.Parameters["CliffTexture"].SetValue(game.Content.Load<Texture2D>("Textures\\cliff"));
            effect.GroundTexture = this.grass;
            effect.MountainTexture = this.mountain;
            effect.MudTexture = this.mud;
            effect.AmbientColor = Vector3.One;
            effect.SpecularColor = new Vector3(1,1, 1);
            effect.SpecularPower = 100;
            effect.LightDirection = new Vector3(0, 1, -1);
            base.effect = effect;
        }

        public override void Update(GameTime gameTime, ref Matrix world)
        {
            base.UpdateWorld(ref world);
            float heightOver4 = (this.maxHeight / 5f);
            BasicTerrainShader shader = (base.effect as BasicTerrainShader);
            shader.GroundAltitudeStart = this.position.Y + heightOver4;
            shader.GroundAltitudeEnd = this.position.Y + (heightOver4 * 2);
            shader.MountainAltitudeStart = this.position.Y + (heightOver4 * 3);
            shader.MountainAltitudeEnd = this.position.Y + ((heightOver4 * 4));

            base.Update(gameTime, ref world);
        }

        /// <summary>
        /// Gets the position offset.
        /// </summary>
        public Vector2 Offset
        {
            get { return this.offset; }
        }

        /// <summary>
        /// Gets the size of the terrain.
        /// </summary>
        public Vector2 Size
        {
            get { return this.size; }
        }

        /// <summary>
        /// Gets the number of vertices in the Y dimension.
        /// </summary>
        public int VerticalVertices
        {
            get { return verticalVertices; }
        }

        /// <summary>
        /// Gets the number of vertices in the X dimension.
        /// </summary>
        public int HorizontalVertices
        {
            get { return horizontalVertices; }
        }

        /// <summary>
        /// Gets the horizontal spacing between each vertex.
        /// </summary>
        public float HorizontalSpacing
        {
            get { return this.horizontalSpacing; }
        }

        /// <summary>
        /// Gets the vertical spacing between each vertex.
        /// </summary>
        public float VerticalSpacing
        {
            get { return this.verticalSpacing; }
        }
    }
}
